package ${package.ServiceImpl};

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.song.tools.core.util.ObjectUtils;
<#if poiServiceImpl??>
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import jakarta.servlet.http.HttpServletResponse;
</#if>
import com.song.tools.mvc.request.BatchIdRequest;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.song.tools.core.exception.BusinessException;
import com.song.tools.core.exception.ExceptionCodeEnum;
import com.song.tools.mvc.request.PageRequest;
import com.song.tools.mvc.response.DeleteResponse;
import com.song.tools.mvc.response.PageResponse;
import com.song.tools.mvc.validator.ValidationException;
import com.song.tools.mvc.validator.ValidationResult;
import ${package.Bo}.${BoName};
<#if poiServiceImpl??>
import ${package.ExportDto}.${ExportDtoName};
import ${package.ImportDto}.${ImportDtoName};
</#if>
import ${package.Entity}.${entity};
import ${package.Query}.${QueryName};
import ${package.QueryRequest}.${QueryRequestName};
import ${package.SaveRequest}.${SaveRequestName};
import ${package.UpdateRequest}.${UpdateRequestName};
import ${package.DeleteResponse}.${DeleteResponseName};
import ${package.QueryResponse}.${QueryResponseName};
import ${package.SaveResponse}.${SaveResponseName};
import ${package.UpdateResponse}.${UpdateResponseName};
import ${package.Convertor}.${ConvertorName};
import ${package.Manager}.${ManagerName};
import ${package.Service}.${ServiceName};
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
<#if poiServiceImpl??>
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
</#if>
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * ${table.comment!} 服务实现类
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
@Slf4j
@Service
public class ${ServiceImplName} implements ${ServiceName} {

    @Resource
    private ${ManagerName} ${entityLowerCaseFirstOne}Manager;

    @Resource
    private ${ConvertorName} ${entityLowerCaseFirstOne}Convertor;

    private static final Map<${stringStr}, SFunction<${EntityName}, ?>> COLUMNS_FUNCTION_MAP;
    static {
        COLUMNS_FUNCTION_MAP = Map.of(
                "${primaryKeyName}", ${EntityName}::get${primaryKeyNameUpperCaseFirstOne}
        );
    }


    /**
     * 通过主键列表批量删除
     *
     * @param request 主键列表请求体
     * @return 删除结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ${DeleteResponseName} deleteByPrimaryKeys(BatchIdRequest<${PrimaryKeyType}> request) {
        List<${PrimaryKeyType}> primaryKeys = request.getIds();
        if (CollUtil.isEmpty(primaryKeys)) {
            throw new BusinessException(ExceptionCodeEnum.PARAM_NOT_NULL);
        }

        // 如果列表很大，考虑分批删除以减轻数据库压力
        int batchSize = 100; // 每批处理100条
        int totalDeleted = 0; // 记录总共删除的行数

        for (int i = 0; i < primaryKeys.size(); i += batchSize) {
            int toIndex = Math.min(i + batchSize, primaryKeys.size());
            List<${PrimaryKeyType}> batchKeys = primaryKeys.subList(i, toIndex);

            int rows = ${entityLowerCaseFirstOne}Manager.deleteBatchByPrimaryKeys(batchKeys);
            totalDeleted += rows;
        }

        ${DeleteResponseName} response = new ${DeleteResponseName}();
        response.setDeleted(totalDeleted > 0 ? DeleteResponse.DELETED_SUCCESS : DeleteResponse.DELETED_FAIL);
        return response;
    }


    /**
     * 通过唯一key查询单个数据
     *
     * @param uniqueKey 唯一键
     * @param column    列名
     * @return 单个数据查询响应结果
     */
    @Override
    public ${QueryResponseName} getOneByUniqueKey(Object uniqueKey, String column) {
        // 根据业务ID查询
        ${BoName} ${entityLowerCaseFirstOne}Bo = ${entityLowerCaseFirstOne}Manager.getOneByUniqueKey(uniqueKey, COLUMNS_FUNCTION_MAP.getOrDefault(column, ${EntityName}::get${primaryKeyNameUpperCaseFirstOne}));
        return ${entityLowerCaseFirstOne}Convertor.entityBoToQueryResponse(${entityLowerCaseFirstOne}Bo);
    }

    /**
     * 查询信息（不分页）
     *
     * @param request 请求
     * @return 响应
     */
    @Override
    public List<${QueryResponseName}> list(${QueryRequestName} request) {
        ${EntityName}Query ${entityLowerCaseFirstOne}Query = ${entityLowerCaseFirstOne}Convertor.queryRequestToQuery(request);
        if (ObjectUtils.isNotEmpty(${entityLowerCaseFirstOne}Query)) {
            List<${BoName}> ${entityLowerCaseFirstOne}List = ${entityLowerCaseFirstOne}Manager.list(${entityLowerCaseFirstOne}Query);
            if (ObjectUtils.isNotEmpty(${entityLowerCaseFirstOne}List)) {
                return ${entityLowerCaseFirstOne}List.stream()
                        .map(${entityLowerCaseFirstOne}Convertor::entityBoToQueryResponse)
                        .filter(ObjectUtils::isNotEmpty)
                        .collect(Collectors.toList());
            }
        }
        return Collections.emptyList();
    }


    /**
     * 查询信息（分页）
     *
     * @param request 请求
     * @return PageResponse 响应
     */
    @Override
    public PageResponse<${QueryResponseName}> listPages(PageRequest<${QueryRequestName}> request) {
        try {
            // 分页查询
            IPage<${BoName}> ${entityLowerCaseFirstOne}Page = ${entityLowerCaseFirstOne}Manager.page(transformToQuery(request));

            // 安全地处理分页转换逻辑
            return safelyConvertPage(${entityLowerCaseFirstOne}Page);
        } catch (Exception e) {
            log.error("查询失败", e);
            throw new BusinessException(ExceptionCodeEnum.SELECT_ERROR);
        }
    }


    /**
     * 安全地将分页数据转换为响应对象
     *
     * @param ${entityLowerCaseFirstOne}Page 分页查询结果
     * @return 分页响应对象
     */
    private PageResponse<${QueryResponseName}> safelyConvertPage(IPage<${BoName}> ${entityLowerCaseFirstOne}Page) {
        if (${entityLowerCaseFirstOne}Page == null || ${entityLowerCaseFirstOne}Page.getRecords() == null) {
            return new PageResponse<>();
        }

        // 使用并行流进行转换以提高效率，但需确保线程安全
        List<${QueryResponseName}> responses = ${entityLowerCaseFirstOne}Page.getRecords().parallelStream()
            .map(${entityLowerCaseFirstOne}Bo -> ${entityLowerCaseFirstOne}Convertor.entityBoToQueryResponse(${entityLowerCaseFirstOne}Bo))
            .collect(Collectors.toList());

        return PageResponse.convertPage(${entityLowerCaseFirstOne}Page, responses);
    }


    /**
     * 将请求 request 转换成 manager 的 query 对象
     *
     * @param request 请求参数
     * @return query 对象
     */
    private PageRequest<${QueryName}> transformToQuery(PageRequest<${QueryRequestName}> request) {
        ${QueryName} ${entityLowerCaseFirstOne}Query = ${entityLowerCaseFirstOne}Convertor.queryRequestToQuery(request.getData());
        return new PageRequest<>(request.getPageNum(), request.getPageSize(), ${entityLowerCaseFirstOne}Query);
    }


    /**
     * 新增
     *
     * @param saveRequest 请求入参
     * @return 响应
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ${SaveResponseName} save(${SaveRequestName} saveRequest) {
        // 校验请求入参
        ValidationResult validationResult = validateOnSave(saveRequest);
        if (!validationResult.isValid()) {
            throw ValidationException.message(validationResult.getErrorMessage());
        }

        // 根据入参封装 BO对象
        ${BoName} ${entityLowerCaseFirstOne}Bo = ${entityLowerCaseFirstOne}Convertor.saveRequestToEntityBo(saveRequest);

        // 数据库操作：插入数据
        int rows = ${entityLowerCaseFirstOne}Manager.save(${entityLowerCaseFirstOne}Bo);

        // 处理插入结果
        boolean saveSuccess = rows > 0;
        // 新增数据成功，返回结果
        if (saveSuccess) {
            // 修改后的数据通过数据库查询返回
            ${BoName} saved${BoName} = ${entityLowerCaseFirstOne}Manager.getOneByUniqueKey(${entityLowerCaseFirstOne}Bo.get${primaryKeyNameUpperCaseFirstOne}(), ${EntityName}::get${primaryKeyNameUpperCaseFirstOne});
            return ${entityLowerCaseFirstOne}Convertor.entityBoToSaveResponse(saved${BoName});
        }

        // 新增数据失败，抛出异常
        throw new BusinessException(ExceptionCodeEnum.CREATE_ERROR);
    }

   /**
    * 修改
    *
    * @param updateRequest 请求
    * @return 响应
    */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ${UpdateResponseName} update(${UpdateRequestName} updateRequest) {
        // 校验请求入参
        ValidationResult validationResult = validateOnUpdate(updateRequest);
        if (!validationResult.isValid()) {
            throw ValidationException.message(validationResult.getErrorMessage());
        }

        // 根据入参封装 BO对象
        ${BoName} ${entityLowerCaseFirstOne}Bo = ${entityLowerCaseFirstOne}Convertor.updateRequestToEntityBo(updateRequest);

        // 数据库操作：修改数据
        int rows = ${entityLowerCaseFirstOne}Manager.updateByPrimaryKey(${entityLowerCaseFirstOne}Bo);

        // 处理修改结果
        boolean updateSuccess = rows > 0;
        // 修改数据成功，返回结果
        if (updateSuccess) {
            // 修改后的数据通过数据库查询返回
            ${BoName} updated${BoName} = ${entityLowerCaseFirstOne}Manager.getOneByUniqueKey(${entityLowerCaseFirstOne}Bo.get${primaryKeyNameUpperCaseFirstOne}(), ${EntityName}::get${primaryKeyNameUpperCaseFirstOne});
            return ${entityLowerCaseFirstOne}Convertor.entityBoToUpdateResponse(updated${BoName});
        }

        // 修改数据失败，抛出异常
        throw new BusinessException(ExceptionCodeEnum.UPDATE_ERROR);
    }


    <#if poiServiceImpl??>
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importExcel(MultipartFile file) {
        try {
            // 默认每次会读取100条数据
            EasyExcel.read(file.getInputStream(), ${ImportDtoName}.class, new PageReadListener<${ImportDtoName}>(importDtos -> {
                ValidationResult validationResult = validateOnImport(importDtos);
                if (!validationResult.isValid()) {
                    throw ValidationException.message(validationResult.getErrorMessage());
                }

                // 数据转换
                List<${BoName}> ${entityLowerCaseFirstOne}Bos = ${entityLowerCaseFirstOne}Convertor.importDtoToEntityBo(importDtos);
                // 保存到数据库
                ${entityLowerCaseFirstOne}Manager.saveBatch(${entityLowerCaseFirstOne}Bos);
            })).sheet().doRead();
        } catch (Exception e) {
            log.warn("上传文件异常 {}", e.getLocalizedMessage(), e);
            throw new BusinessException(ExceptionCodeEnum.IMPORT_ERROR);
        }
    }


    @Override
    public void importTpl(HttpServletResponse response) {
        try {
            // 设置相应格式
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setCharacterEncoding("utf-8");

            // URLEncoder.encode 可以防止中文乱码
            String filename = "${table.comment}_导入模版_" + LocalDateTime.now();
            filename = URLEncoder.encode(filename, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=" + filename + ".xlsx");
            try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), ${ImportDtoName}.class).autoCloseStream(false).build()) {
                WriteSheet writeSheet = EasyExcel.writerSheet("sheet").build();
                excelWriter.write(Collections.emptyList(), writeSheet);
            }
        } catch (Exception e) {
            log.warn("导出模版异常 {}", e.getLocalizedMessage(), e);
            throw new RuntimeException(e);
        }
    }


    @Override
    public void export(HttpServletResponse response, ${QueryRequestName} queryRequest) throws IOException {
        try {
            // 设置相应格式
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setCharacterEncoding("utf-8");

            // 分页请求
            PageRequest<${QueryRequestName}> pageRequest = new PageRequest<>();
            pageRequest.setData(queryRequest);
            pageRequest.setPageSize(500);
            pageRequest.setPageNum(1);

            PageRequest<${QueryName}> pageQuery = transformToQuery(pageRequest);

            // URLEncoder.encode 可以防止中文乱码
            String filename = "${table.comment}_" + LocalDateTime.now();
            filename = URLEncoder.encode(filename, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=" + filename + ".xlsx");
            try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), ${ExportDtoName}.class).autoCloseStream(false).build()) {
                WriteSheet writeSheet = EasyExcel.writerSheet("sheet").build();

                long totalPage = 0;
                while (true) {
                    // 从数据库中读取数据
                    IPage<${BoName}> ${entityLowerCaseFirstOne}Page = ${entityLowerCaseFirstOne}Manager.page(pageQuery);
                    if (${entityLowerCaseFirstOne}Page.getTotal() > 100_000) {
                        throw new BusinessException(ExceptionCodeEnum.EXPORT_TOO_MUCH);
                    }
                    if (${entityLowerCaseFirstOne}Page.getPages() != 0) {
                        totalPage = ${entityLowerCaseFirstOne}Page.getPages();
                    }

                    // 查到的结果为空
                    if (${entityLowerCaseFirstOne}Page.getRecords().isEmpty()) {
                        break;
                    }

                    // 写入到 excel 中
                    List<${ExportDtoName}> exportVos = ${entityLowerCaseFirstOne}Page.getRecords().stream().map(${entityLowerCaseFirstOne}Convertor::entityBoToExportDto).collect(Collectors.toList());
                    excelWriter.write(exportVos, writeSheet);

                    // 没有下一页，跳出循环
                    if (${entityLowerCaseFirstOne}Page.getCurrent() >= totalPage) {
                        break;
                    }

                    // 请求下一页
                    pageRequest.setPageNum(pageRequest.getPageNum() + 1);
                }
            }
        } catch (Exception e) {
            log.warn("导出文件异常 {}", e.getLocalizedMessage(), e);
            throw new BusinessException(ExceptionCodeEnum.EXPORT_ERROR);
        }
    }
    </#if>
}
